# -*- coding: utf-8 -*-

from autoadmin.lib.exceptions import NextIteration, InstanceSchemaNotFound

import logging, types

from UserDict import IterableUserDict

class ManipulatorSchema(IterableUserDict):
    """ Схема поведения манипулятора,
    должна описывать, что делает манипулятор с различными типами полей """

    def get_instance_schema(self, instance):
        try:
            return self[instance.__class__]
        except KeyError:
            try:
                getattr(instance, '_sa_session_id')
            except AttributeError:
                raise InstanceSchemaNotFound
            else:
                return self.default_schema

class Manipulator(object):
    
    @staticmethod
    def filter(value, filter_list=None):
        """Простой фильтр значений списка.
        Возвращает True в случае если значения нет в списке.
        False, если значение в списке присутсвует.
        """
        
        if filter_list is None:
            return True
        
        try:
            filter_list.index(value)
        except ValueError:
            return True
        return False
        
    def __init__(self, m_object, m_schema):
        self.m_object = m_object
        self.m_schema = m_schema

class FieldManipulator(Manipulator):
    
    def get_m_object_schema(self):
        self.m_object_schema = self.m_schema.get_instance_schema(self.m_object)
    
    def get_field_filter_list(self):
        if not self.m_object_schema.field_filter is None:
            self.filter = self.m_object_schema.field_filter
        self.field_filter_list = self.m_object_schema.field_filter_list

    def get_instance(self, attr_name):
        # вначале смотрим, доступна ли колонка или 
        # же только её значение или это совсем не колонка а добавленное
        # маппером поле
        #
        # Если это колонка, возвращаем объект колонки и значение колонки
        #
        try:
            args = getattr(self.m_object.c, attr_name)
        except AttributeError:
            args = None
                
        instance = getattr(self.m_object, attr_name)
        
        return (instance, args)
        
    def process_instance(self, instance, args):
        log = logging.getLogger('%s.%s.%s' % (__name__, self.__class__.__name__, 'process_instance'))

        log.debug('instance of type: %s with args %s' % (type(instance),
                                                                 type(args)))

        # проверяем, что атрибут не метод
        # елси метод, просим следующей итерации
        if isinstance(instance, types.MethodType):
            raise NextIteration

        swaped = False
        if args != None:
            swaped = True
            args, instance = (instance, args)

        try:
            schema = self.m_schema.get_instance_schema(instance)
                    
            if swaped:
                args, instance = (instance, args)
                
            retval = schema.handler(instance, args)

        except InstanceSchemaNotFound:
            log.debug("Schema not found for: %s" % instance)
            raise NextIteration
        
        return retval
    
    def manipulate(self):

        form_fields = []
                    
        self.get_m_object_schema()
        self.get_field_filter_list()

        for attr_name in dir(self.m_object):
            if not attr_name.startswith('_') and self.filter(attr_name, self.field_filter_list):
                
                instance, args = self.get_instance(attr_name)
                
                try:
                    form_field = self.process_instance(instance, args)
                except NextIteration:
                    continue
                
                form_fields.append(form_field)
                
        return form_fields

class NewManipulator(object):
    
    def __init__(self, model_object, fields_manipulate_schemas_container, 
            models_manipulate_schemas_container):
        
        self.model_object = model_object
        self.fields_manipulate_schemas_container = fields_manipulate_schemas_container
        self.models_manipulate_schemas_container = models_manipulate_schemas_container
        
        self.model_manipulate_schema = None
        
    @staticmethod
    def filter(value, filter_list=None):
        """Простой фильтр значений списка.
        Возвращает True в случае если значения нет в списке.
        False, если значение в списке присутсвует.
        """
        
        if filter_list is None:
            return True
        
        try:
            filter_list.index(value)
        except ValueError:
            return True
        return False
    
    #def get_field_filter_list(self):
    #    if not self.model_manipulate_schema.field_filter is None:
    #        self.filter = self.model_manipulate_schema.field_filter
    #    self.field_filter_list = self.model_manipulate_schema.field_filter_list        
    
    def get_model_manipulate_schema(self):
        self.model_manipulate_schema = self.models_manipulate_schemas_container.\
                get_instance_schema(self.model_object)
                
    def get_instance(self, attr_name):
        # вначале смотрим, доступна ли колонка или 
        # же только её значение или это совсем не колонка а добавленное
        # маппером поле
        #
        # Если это колонка, возвращаем объект колонки и значение колонки
        #
        try:
            args = getattr(self.model_object.c, attr_name)
        except AttributeError:
            args = None

        instance = getattr(self.model_object, attr_name)
        
        return (instance, args)
    
    def process_instance(self, instance, args):
        log = logging.getLogger('%s.%s.%s' % (__name__, self.__class__.__name__, 'process_instance'))

        log.debug('instance of type: %s with args %s' % (type(instance),
                                                                 type(args)))

        # проверяем, что атрибут не метод
        # елси метод, просим следующей итерации
        if isinstance(instance, types.MethodType):
            raise NextIteration

        swaped = False
        if args != None:
            swaped = True
            args, instance = (instance, args)

        try:
            schema = self.fields_manipulate_schemas_container.get_instance_schema(instance)

            if swaped:
                args, instance = (instance, args)
                
            retval = schema(instance, args)

        except InstanceSchemaNotFound:
            log.debug("Schema not found for: %s" % instance)
            raise NextIteration
        
        return retval
    
    def manipulate(self):

        form_fields = []
        
        self.get_model_manipulate_schema()

        for attr_name in dir(self.model_object):
            if not attr_name.startswith('_') and \
            self.filter(attr_name, self.model_manipulate_schema.field_filter_list):
                instance, args = self.get_instance(attr_name)
                
                try:
                    form_field = self.process_instance(instance, args)
                except NextIteration:
                    continue
                
                form_fields.append(form_field)
                
        return form_fields    
